package com.googlecode.ws.tester.xor.engine;

import org.apache.commons.lang.StringUtils;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import org.xml.sax.Attributes;
import com.googlecode.ws.tester.xor.engine.model.Namespace;

import java.util.*;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

/**
 * Created by IntelliJ IDEA.
 * User: pablo
 * Date: 2009-06-08
 * Time: 20:25:54
 */
public class SAXEventHandler extends DefaultHandler {

    private List<Namespace> namespaces = new ArrayList<Namespace>();
    private Config config;
    private Deque<Object> elements = new ArrayDeque<Object>();
    private Object root;

    public Config getConfig() {
        return config;
    }

    public void setConfig(Config config) {
        this.config = config;
    }

    @Override
    public void startPrefixMapping(String prefix, String uri) throws SAXException {
        Namespace namespace = new Namespace();
        namespace.setPrefix(prefix);
        namespace.setUri(uri);
        namespaces.add(namespace);
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if (config.getElements().containsKey(localName)) {
            Element element = config.getElements().get(localName);
            try {
                Class<?> aClass = Class.forName(element.getClassName());
                Object o = aClass.newInstance();
                Object parent = null;
                if (!elements.isEmpty()) {
                    parent = elements.peek();
                }
                elements.push(o);
                if (Boolean.valueOf(element.getRoot())) {
                    root = o;
                }
                if (Boolean.valueOf(element.getNamespaces())) {
                    Method[] methods = aClass.getMethods();
                    for (Method m : methods) {
                        if (m.getName().equals("setNamespaces")) {
                            m.invoke(o, namespaces);
                            namespaces = new ArrayList<Namespace>();
                            break;
                        }
                    }
                }
                if (!Boolean.valueOf(element.getRoot())) {
                    String methodName = "";
                    if (Boolean.valueOf(element.getCollection())) {
                        methodName = "add" + StringUtils.capitalize(localName);
                    } else {
                        methodName = "set" + StringUtils.capitalize(localName);
                    }
                    try {
                    Method method = parent.getClass().getMethod(methodName, o.getClass());
                    method.invoke(parent, o);
                    } catch (NoSuchMethodException nsme) {

                    }
                }

                if (attributes.getLength() > 0) {
                    int attrLength = attributes.getLength();
                    for (int i = 0; i < attrLength; i++) {
                        Method[] methods = o.getClass().getMethods();
                        String methodName = "set" + StringUtils.capitalize(attributes.getLocalName(i));
                        for (Method method : methods) {
                            if (method.getName().equals(methodName)) {
                                method.invoke(o, attributes.getValue(i));
                            }
                        }
                    }
                }
            } catch (ClassNotFoundException e) {
                System.out.println(e.getMessage());
            } catch (IllegalAccessException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (InvocationTargetException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (InstantiationException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } 
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (config.getElements().containsKey(localName)) {
            elements.pop();
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        try {
            Object o = elements.peek();
            Method m = o.getClass().getMethod("setValue", String.class);
            char[] tmp = Arrays.copyOfRange(ch, start, start+length);
            m.invoke(o, new String(tmp));
        } catch (NoSuchMethodException e) {
            
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    public Object getRoot() {
        return root;
    }
}
